import logging
import re
import uuid
import sys
import os
import urllib2
import config
import HTMLParser
import string
import random

class Error(Exception):
    """Base class for exceptions in this module."""
    pass
    

from google.appengine.api        import mail
from google.appengine.api        import memcache
from google.appengine.ext        import webapp
from google.appengine.ext        import db
from google.appengine.ext.webapp import template
from lib.model.Mech              import Mech
from lib.model.Mechs             import Mechs
from lib.model.Player            import Player
from lib.model.Players           import Players
from lib.model.Message           import Message
from lib.model.Mechnames         import Mechnames
from lib.model.Videos            import Tutorials, Instructions
from lib.Smurfy                  import Mechs as WebMechs, Weapons as WebWeapons, Modules as WebModules, Mech as WebMech
from lib.Toolbox                 import WebTools
from lib.TJSON                   import TJSON



class Error(Exception):
    """Base class for exceptions in this module."""
    pass
    



logging.basicConfig(level=logging.DEBUG)
# logging.info(os.path.join(os.path.dirname(__file__), 'lib'))

import datetime
import json
from datetime import datetime



class MechFromSmurfyHandler(webapp.RequestHandler):
    def get(self):
        url = self.request.get('u')
        tst = re.search('(i=\d+&l=[0-9a-z]+)', url)
        
        if ( tst ):
            url = "http://mwo.smurfy-net.de/tools/mechtooltip?" + tst.group(1)

            mech = WebMech.fetch(url)
            self.response.headers["Content-Type"] = "application/json"
            self.response.out.write(json.dumps(mech))
        
class RandomMechnameHandler(webapp.RequestHandler):

    def get(self):
        names = Mechnames.mechnames()
        count = len(names)
        index = random.randint(0,count)
        self.response.headers["Content-Type"] = "text/plain"
        self.response.out.write(names[index])


class DateHandler(webapp.RequestHandler):

    def get(self):
        dropid  = self.request.get('d')
        logging.info("date.get: /d?d=%s", dropid )
        date    = None
  
        #memcache.set("D"+dropid, datetime.now().isoformat(),  5 * 60 )
        logging.info("date.get: FROMCACHE: D" + dropid )
        date = memcache.get("D" + dropid)
  
        if date:
            
            self.response.out.write(date)
        else:
            logging.info("date.get: not found")
            self.response.out.write("X")
        
        
class IndexHandler(webapp.RequestHandler):

    @classmethod
    def uid(self):
        s = uuid.uuid4().hex;
        s = s[0:6];
        return s

    def get(self):
        self.response.out.write(template.render("templates/index.html", self.process_get() ))
 
    def process_get(self):
        
        dropid  = self.request.get('d')

        return {
            'mechs':           None,
            'starter':         '',
            'method':          'get',
            'mech':            { 'dropid': dropid, 'player': '' },
            'drop_totals':     { 'active_players': 0, 'active_tonnage': 0, 'total_players':  0, 'total_tonnage':  0 },
            'home':            True,
            'dropid':          dropid,
            'proposed_dropid': self.uid(),
            'config':          config.Config(),
            'tutorials':       Tutorials.list(),
            'instructions':    Instructions.list()
        }


    def post(self):
        #logging.basicConfig(filename='example.log',level=logging.DEBUG)
        logging.info("POST: /")
        i = self.request.get('i', default_value="");
        t = "templates/roster.html" if i else "templates/index.html"
        self.response.out.write(template.render(t, self.process_post() ))

    def process_post(self):
        dropid         = self.request.get('d', default_value="") 
        player         = self.request.get('p', default_value="").strip()
        mechtype       = self.request.get('m', default_value="").strip()
        name           = self.request.get('n', default_value="").strip()
        speed          = self.request.get('sp', default_value=0) 
        action         = self.request.get('a', default_value="")
        players        = WebTools.get_array(self.request, 'players')
        weapons        = WebTools.get_array(self.request, 'w')
        modules        = WebTools.get_array(self.request, 'e', unique=True, sort=True)
        position       = self.request.get("pos", default_value=0)
        logging.info("process_post: dropid: %s / player: %s / mechtype: %s ", dropid, player, mechtype)
        
        if not dropid: dropid = self.uid()
        # mechlist       = Mechs.mechs_by_dropid(dropid)
        # mech           = {'dropid': dropid, 'player': ''}
        args = { 'mechlist': Mechs.mechs_by_dropid(dropid), 'mech': None, 'dirty': 0     }
     
        if args['mechlist'] == None:
            logging.info("process_post: mechlist: None")
        
        try:
            if len(args['mechlist']) == 0:
                logging.info("process_post: mechlist: Empty")
            else:
                logging.info("process_post: mechlist: %s", len(args['mechlist']))
        except:
            logging.info("process_post ???: mechlist: %s", args['mechlist'])
        
        if not player:
            logging.info("process_post: no player")
            logging.info("add_mech: mechlist before return: %s", len(args['mechlist']))
            return self.post_drop_data(dropid, '', args['mech'], args['mechlist'])


        logging.info("process_post: finding mech")
        args['mech'] = Mechs.find_mech(dropid, name, player, args)

        if ( not args['mech'] ):
            logging.info("process_post: mech not found, saving...")
            args['mech'] = Mechs.save_mech(dropid, speed, mechtype, name, position, player, modules, weapons, args)
            logging.info("process_post: mechlist after save: %s", len(args['mechlist']))
        # 
        logging.info("process_post: process_actions") 
        self.process_actions( dropid, players, action, speed, mechtype, name, position, player, modules, weapons, args )
        logging.info("process_post: mechlist after actions: %s", len(args['mechlist']))
        
        if not args['mech']:
            logging.info("process_post: new mech ")
            args['mech'] = Mechs.add_mech(dropid, speed, mechtype, name, position, player, modules, weapons, args)
            logging.info("process_post: mechlist after add: %s", len(args['mechlist']))
        else:
            for m in args['mechlist']:
                if m.player == player:
                    args['mech'] = m
                    break
        
        if args['mech']:
            logging.info("process_post with mech: %s", args['mech'].player)
        else:
            logging.info("process_post with mech")
        
        return self.post_drop_data(dropid, player, args['mech'], mechlist=args['mechlist'])
    
   
    #
    # Process actions like Lance Assignment, Assign lead and Player removal
    #
    def process_actions(self, dropid, players, action, speed, mechtype, name, position, player, modules, weapons, args):
        
        logging.info("process_actions: action %s players: [%s]", action, ",".join(players))    

        if action == "s":
            logging.info("process_actions: save_mech")
            args['mech'] = Mechs.save_mech(dropid, speed, mechtype, name, position, player, modules, weapons, args)
            logging.info("process_actions: mechlist after save: %s", len(args['mechlist']))
            return True
        elif action and len(players) > 0:
            logging.info("process_actions: apply action and return new list")
          
            if action == "l":
                args['mech'] = Mechs.set_dropleader(dropid, players[0], mechlist=args['mechlist'])
                return True
            elif action == "x":
                Mechs.remove_player(dropid, players, mechlist=args['mechlist'])
                return True
            elif action != "":
                lance   = { "a":"Alpha", "b":"Bravo", "c":"Charlie", "d":"Delta", "r":"Reserve", "l":"", "x":"" }[action]
                Mechs.assign_lance(dropid, players, lance, mechlist=args['mechlist'])
                return True
            else:        
                logging.info("process_actions: no action")
        return False
   
    def post_drop_data(self, dropid, player, mech, mechlist):
        visiting  = self.request.get('v', default_value="0")
        dbplayer  = Players.player_by_name(player)
        
        if visiting == "1":
            dbplayer.visits = dbplayer.visits + 1
            dbplayer.put()
        
        return {
            'method':           'post',
            'dropid':           dropid,
            'player':           dbplayer,
            'mech':             mech,
            'mechs':            mechlist,
            'tutorials':        Tutorials.list(),
            'instructions':     Instructions.list(),
            'tonnages':         WebMechs.list(),
            'tonnagesGrouped':  WebMechs.list_grouped_by_class(),
            'starter':          Mechs.drop_leader(dropid, mechlist),
            'garage':           Mechs.named_mechs_by_player(player),
            'weapons':          WebWeapons.list(),
            'modules':          WebModules.list(),
            'config':           config.Config(),
            'drop_totals':      self.calculate_drop_totals(mechlist),
            'mech_classes':     ['Light', "Medium", "Heavy", "Assault", "Special"],
            'speeds':           [40, 50, 60, 70, 80, 90, 100, 110, 120, 130, 140, 150, 160, 170],
        }
    
    #
    # Calculate tonnage totals
    #
    def calculate_drop_totals(self, mechlist):
        active_players = 0
        active_tonnage = 0
        total_players  = 0
        total_tonnage  = 0
        
        tonnages = WebMechs.list()

        for m in mechlist:
            if m.lance:
                total_players = total_players + 1
                if m.mechtype:
                    total_tonnage = total_tonnage + tonnages[WebTools.utf8_ify(m.mechtype)]
                if m.lance != "Reserve":
                    active_players = active_players + 1
                    if m.mechtype:
                        active_tonnage = active_tonnage + tonnages[WebTools.utf8_ify(m.mechtype)]

        return {
            'active_players': active_players,
            'active_tonnage': active_tonnage,
            'total_players':  total_players,
            'total_tonnage':  total_tonnage
        }

    def update_cache(self, dropid, list):
        Mechs.put_in_cache(dropid, list, 5 * 60)

  
        
class JsonHandler(IndexHandler):
    def post(self):
        self.response.headers["Content-Type"] = "application/json"
        self.response.out.write( TJSON.json( "templates/dropdata.json", self.process_post() ) )
    
    def get(self):
        self.response.headers["Content-Type"] = "application/json"
        self.response.out.write( TJSON.json( "templates/dropdata.json", self.process_get() ) )
        
class SecondScreenHandler(IndexHandler):
    
    def handle(self, id):
        self.request.GET["d"] = id
        self.response.out.write( unicode(template.render( "templates/roster-simple.html", self.process_post() )) )
    
    def post(self, id):
        self.handle();
        
    def get(self, id):
        self.handle(id);
        
    
class GarageHandler(webapp.RequestHandler):
        
    def post(self):
        logging.info("post: " )
        self.response.out.write( unicode(template.render( "templates/garage.html", self.garage() )))
        
    def get(self):
        logging.info("get: " )
        self.response.out.write( unicode(template.render( "templates/garage.html", self.garage() )))
        
    def garage(self):
        a = self.request.get("a", default_value="")
        p = self.request.get("p", default_value="")
        o = self.request.get('o', default_value="name")
        n = WebTools.utf8_ify(self.request.get("n", default_value=""))
        u = self.request.get("u", default_value="")
        
        if p == "":
            return { "garage": [] }
        
        if a == "x":
            if n == "":
                return { "garage": [] }

            mech = Mechs.mech_by_player_and_name(p, n)
            mech.name   =""
            mech.put()
            
        if a == "r":
            if n == "" or u == "":
                return { "garage": [] }

            mech = Mechs.mech_by_player_and_name(p, n)
            mech.name = WebTools.utf8_ify(u)
            mech.put()
                
        return {
            "garage": Mechs.named_mechs_by_player( p, order=o ),
        }
    


class ContactHandler(webapp.RequestHandler):

    def get(self):
        self.post()
        
    def post(self):
        self.response.headers["Content-Type"] = "text/plain"
        self.response.out.write( self.process_request() )
        
    def process_request(self):
        name  = self.request.get('name'); 
        addi  = self.request.get('mail'); 
        text  = self.request.get('text')
        body  = "id: %s\nmail: %s\nmessage:\n%s" % (name, addi, text)
        
        if not name:
            return 1
        
        if not text:
            return 2
        
        try:
            mail.send_mail(
                sender  = "holli.holzer@gmail.com",
                to      = "holli.holzer@googlemail.com",
                subject = "MW:O Drop Planner: New message",
                body    = body
            )
        except:
            return 3
        
        try:
            dbmessage = Message(text=text, name=name, mail=addi, public=False)
            dbmessage.put()
        except:
            return 4
            
        return 0

class TestHandler(webapp.RequestHandler):
  
    def get(self):
        mechs = Smurfy.Mechs.list( cached=False )
        weapons = Smurfy.Weapons.list( cached=False )
        
        self.response.out.write( unicode(mechs) + unicode(weapons) )
        
class UnknownHandler(webapp.RequestHandler):

    def get(self):
        self.response.out.write(404)
        self.error(404)

class ForbiddenHandler(webapp.RequestHandler):

    def get(self):
        self.response.out.write(400)
        self.error(400)